package Task;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.UUID;

import Object.DSException;

//@author A0105536L
/**
 * DSTask is the class that is used to represent the tasks that the user
 * enters. It stores the various attributes of the task and provides
 * methods to obtain and manipulate these attributes.
 */
public class DSTask implements Comparable<DSTask> {
	
	// These int are used by the getStatus method for easy reading
	public static final int OVERDUE = 1;
	public static final int DONE = 2;
	public static final int NOT_DONE = 3;
	public static final int IN_PROCESS = 4;
	
	public static final int COMPARE_EQUAL = 0;
	public static final int COMPARE_SMALLER_THAN = -1;
	public static final int COMPARE_LARGER_THAN = 1;
	
	/*
	 * Default initialised date/ time for task instance, if date/ time are
	 * equal to these, it means the task does not have a date/time.
	 * 01-01-1111 is the default date as it is assumed that users would add tasks
	 * with dates that fall in the future. Similarly, time will never reach 99:99
	 */
	public static final String DEFAULT_DATE = "01-01-1111";
	public static final int DEFAULT_TIME = 9999;
	
	// To format String into Date and vice versa
	private static DateFormat _formatter = new SimpleDateFormat("MM-dd-yyyy");

	private String _taskId;
	private String _taskName;
	private Date _taskStartDate;
	private Date _taskEndDate;
	private int _taskStartTime;
	private int _taskEndTime;
	private HashSet<String> _tagsSet;
	private boolean _isDone;

	public DSTask() throws ParseException {
		UUID uuid = UUID.randomUUID();
		this._taskId = uuid.toString();

		if (this._formatter == null) {
			this._formatter = new SimpleDateFormat("MM-dd-yyyy");
		}

		this._taskStartDate = this._formatter.parse(DEFAULT_DATE);
		this._taskEndDate = this._formatter.parse(DEFAULT_DATE);
		this._taskStartTime = DEFAULT_TIME;
		this._taskEndTime = DEFAULT_TIME;
		this._tagsSet = new HashSet<String>();
		this._isDone = false;
	}

	// Setter
	public void setTaskId(String taskId) {
		this._taskId = taskId;
	}

	public void setTaskName(String taskName) {
		this._taskName = taskName;
	}

	public void setTaskStartDate(Date taskStartDate) {
		this._taskStartDate = taskStartDate;
	}

	public void setTaskEndDate(Date taskEndDate) {
		this._taskEndDate = taskEndDate;
	}

	public void setTaskStartDate(String taskStartDate) throws ParseException {
		this._taskStartDate = this._formatter.parse(taskStartDate);
		;
	}

	public void setTaskEndDate(String taskEndDate) throws ParseException {
		this._taskEndDate = this._formatter.parse(taskEndDate);
		;
	}

	public void postTaskEndDate(Date taskenddate) {
		this._taskEndDate = taskenddate;
	}

	public void postTaskStartDate(Date taskstartdate) {
		this._taskStartDate = taskstartdate;
	}

	public void setTaskStartTime(int taskStartTime) {
		this._taskStartTime = taskStartTime;
	}

	public void setTaskEndTime(int taskEndTime) {
		this._taskEndTime = taskEndTime;
	}

	public void setTags(String[] tags) {
		for (String tag : tags) {
			addTag(tag);
		}
	}

	public void addTag(String tag) {
		this._tagsSet.add(tag);
	}

	public void setIsDone(boolean status) {
		this._isDone = status;
	}

	// Getter
	public String getTaskId() {
		return this._taskId;
	}

	public String getTaskName() {
		return this._taskName;
	}

	public Date getTaskStartDate() {
		return this._taskStartDate;
	}

	public Date getTaskEndDate() {
		return this._taskEndDate;
	}

	public int getTaskStartTime() {
		return this._taskStartTime;
	}

	public int getTaskEndTime() {
		return this._taskEndTime;
	}

	public Object[] getTaskTags() {
		return this._tagsSet.toArray();
	}

	public int getStatus() {
		Date date = new Date();
		
		if (_isDone) {
			return DONE;
		} else {
			if (!this._taskStartDate.equals(formatStringToDate(DEFAULT_DATE))
					&& !this._taskEndDate.equals(formatStringToDate(DEFAULT_DATE))) {
				// timed task
				Date taskStartDateTime, taskEndDateTime;
				if (hasEndTime()) {
					taskEndDateTime = new Date(_taskEndDate.getYear(), _taskEndDate.getMonth(),
						 												 _taskEndDate.getDate(), _taskEndTime / 100,
						 												 _taskEndTime % 100);
				} else {
					taskEndDateTime = new Date(_taskEndDate.getYear(), _taskEndDate.getMonth(),
																		 _taskEndDate.getDate());
				}
				if (hasStartTime()) {
					taskStartDateTime = new Date(_taskStartDate.getYear(), _taskStartDate.getMonth(),
							 												 _taskStartDate.getDate(), _taskStartTime / 100,
							 												 _taskStartTime % 100);
				} else {
					taskStartDateTime = new Date(_taskStartDate.getYear(), _taskStartDate.getMonth(),
							 												 _taskStartDate.getDate());
				}
				if (taskEndDateTime.compareTo(date) < 0) {
					return OVERDUE;
				} else if (taskStartDateTime.compareTo(date) < 0 &&
									 taskEndDateTime.compareTo(date) >= 0) {
					return IN_PROCESS;
				} else {
					return NOT_DONE;
				}
			} else if (this._taskStartDate.equals(formatStringToDate(DEFAULT_DATE))
					&& !this._taskEndDate.equals(formatStringToDate(DEFAULT_DATE))) {
				Date taskDateTime;
				if (hasEndTime()) {
					taskDateTime = new Date(_taskEndDate.getYear(), _taskEndDate.getMonth(),
				 												  _taskEndDate.getDate(), _taskEndTime / 100,
				 												  _taskEndTime % 100);
				} else {
					taskDateTime = new Date(_taskEndDate.getYear(), _taskEndDate.getMonth(),
							 										_taskEndDate.getDate());
				}
				if (taskDateTime.compareTo(date) < 0) {
				
					return OVERDUE;
				} else
					return NOT_DONE;
			} else
				return NOT_DONE;
		}
	}

	public String getTaskStartDateString() {
		if (_formatter.format(this._taskStartDate).equals(DEFAULT_DATE))
			return "";
		return _formatter.format(this._taskStartDate);
	}

	public String getTaskEndDateString() {
		if (_formatter.format(this._taskEndDate).equals(DEFAULT_DATE))
			return "";
		return _formatter.format(this._taskEndDate);
	}

	public String[] getTaskTagStrings() {
		String string = _tagsSet.toString();
		string = string.substring(1, string.length() - 1);
		return string.split(", ");
	}

	public String getTaskStartTimeString() {
		if (this._taskStartTime == DEFAULT_TIME)
			return "";
		return String.format("%02d", this._taskStartTime / 100) + ":"
				+ String.format("%02d", this._taskStartTime % 100);
	}

	public String getTaskEndTimeString() {
		if (this._taskEndTime == DEFAULT_TIME)
			return "";
		return String.format("%02d", this._taskEndTime / 100) + ":"
				+ String.format("%02d", this._taskEndTime % 100);
	}

	public String getDescription() {
		return "*" + this._taskId + " !" + this._taskName + " >"
				+ this._formatter.format(this._taskStartDate) + " <"
				+ this._formatter.format(this._taskEndDate) + " #"
				+ this._taskStartTime + "-" + this._taskEndTime;
	}

	public String getDescriptionDisplay() {
		return "\n" + "TaskName: " + this._taskName + "\n"
				+ "Date starts from: " + this._taskStartDate + " Ends at: "
				+ this._taskEndDate + "\n" + "Time starts from: "
				+ this._taskStartTime + " Ends at: " + this._taskEndTime;
	}

	public boolean hasTaskName() {
		return this._taskName != null;
	}
	
	//@author A0094762W
	public boolean hasStartDate() {
		String startDateStr = formatDateToString(this._taskStartDate);
		return !startDateStr.equals(DEFAULT_DATE);
	}

	public boolean hasEndDate() {
		String endDateStr = formatDateToString(this._taskEndDate);
		return !endDateStr.equals(DEFAULT_DATE);
	}

	public boolean hasStartTime() {
		return this._taskStartTime != DEFAULT_TIME;
	}

	public boolean hasEndTime() {
		return this._taskEndTime != DEFAULT_TIME;
	}
	
	//@author A0105536L
	public boolean isDone() {
		return this._isDone;
	}

	public boolean hasTags() {
		return !_tagsSet.isEmpty();
	}

	public boolean isOverdue() throws ParseException {
		Date Date = new Date();
		if (this._taskEndDate.compareTo(Date) < 0) {
			return true;
		} else
			return false;
	}

	public boolean containsTag(String tag) {
		return _tagsSet.contains(tag);
	}

	//@author A0105536L
	/**
	 * This method is to count days between start date and current date
	 * 
	 * @return Long integer
	 * @throws ParseException
	 */
	public long start_minus_today() throws ParseException {
		if (!this._taskStartDate.equals(_formatter.parse(DEFAULT_DATE))) {
			Date date = new Date();
			Date taskDateTime;
			if (hasStartTime()) {
				taskDateTime = new Date(_taskStartDate.getYear(), _taskStartDate.getMonth(),
						 										_taskStartDate.getDate(), _taskStartTime / 100,
						 										_taskStartTime % 100);
			} else {
				taskDateTime = new Date(_taskStartDate.getYear(), _taskStartDate.getMonth(),
						 										_taskStartDate.getDate());
			}
			return (taskDateTime.getTime() - date.getTime())/10000;
		} else
			return -1;
	}

	/**
	 * This method is to count days between end date and current date
	 * 
	 * @return Long integer
	 * @throws ParseException
	 */
	public long end_minus_today() throws ParseException {
		if (!this._taskEndDate.equals(_formatter.parse(DEFAULT_DATE))) {
			Date date = new Date();
			Date taskDateTime;
			if (hasEndTime()) {
				taskDateTime = new Date(_taskEndDate.getYear(), _taskEndDate.getMonth(),
						 										_taskEndDate.getDate(), _taskEndTime / 100,
						 										_taskEndTime % 100);
			} else {
				taskDateTime = new Date(_taskEndDate.getYear(), _taskEndDate.getMonth(),
						 										_taskEndDate.getDate());
			}
			System.out.println((taskDateTime.getTime() - date.getTime())/10000);
			return (taskDateTime.getTime() - date.getTime())/10000;
		} else
			return -1;
	}

	/**
	 * This method is to format end date and end time
	 * 
	 * @return Return a string
	 */
	public String EndDateandTime() {
		String Endresult = "";
		if (!_formatter.format(this._taskEndDate).equals(DEFAULT_DATE))
			Endresult += formatToDate(_formatter.format(this._taskEndDate));
		if (this._taskEndTime != DEFAULT_TIME)
			Endresult += ", " + String.format("%02d", this._taskEndTime / 100)
					+ ":" + String.format("%02d", this._taskEndTime % 100);
		return Endresult;
	}

	/**
	 * This method is to format start date and start time
	 * 
	 * @return Return a string
	 */
	public String StartDateandTime() {
		String Startresult = "";
		if (!_formatter.format(this._taskStartDate).equals(DEFAULT_DATE))
			Startresult += formatToDate(_formatter.format(this._taskStartDate));

		if (this._taskStartTime != DEFAULT_TIME)
			Startresult += ", "
					+ String.format("%02d", this._taskStartTime / 100) + ":"
					+ String.format("%02d", this._taskStartTime % 100);
		return Startresult;
	}

	/**
	 * This method is to format date. e.g Jan 1
	 * 
	 * @param string
	 * @return
	 */
	public String formatToDate(String string) {
		String[] date = string.split("-");
		String returnString = "";
		switch (Integer.parseInt(date[0])) {
		case 1:
			returnString = "Jan " + date[1];
			break;
		case 2:
			returnString = "Feb " + date[1];
			break;
		case 3:
			returnString = "Mar " + date[1];
			break;
		case 4:
			returnString = "Apr " + date[1];
			break;
		case 5:
			returnString = "May " + date[1];
			break;
		case 6:
			returnString = "Jun " + date[1];
			break;
		case 7:
			returnString = "Jul " + date[1];
			break;
		case 8:
			returnString = "Aug " + date[1];
			break;
		case 9:
			returnString = "Sep " + date[1];
			break;
		case 10:
			returnString = "Oct " + date[1];
			break;
		case 11:
			returnString = "Nov " + date[1];
			break;
		case 12:
			returnString = "Dec " + date[1];
			break;
		}
		if(!date[2].equals("2014")){
			 returnString += ", "+date[2].substring(2,4);
		}
		return returnString;
		
	}

	/**
	 * This method is to format the task into a format string
	 * 
	 * @return Return a format string
	 * @throws ParseException
	 */
	public String updateString() throws ParseException {

		return this._taskName
				+ " "
				+ this.showDate()
				+ " tag "
				+ Arrays.toString(this._tagsSet.toArray())
						.substring(
								1,
								Arrays.toString(this._tagsSet.toArray())
										.length() - 1).replaceAll(",", "");
	}

	//@author A0103535R
	public DSTask copy() throws ParseException {
		DSTask copy = new DSTask();
		copy._taskId = this._taskId;
		copy._taskName = this._taskName;
		copy._taskStartDate = (Date) this._taskStartDate.clone();
		copy._taskEndDate = (Date) this._taskEndDate.clone();
		copy._taskStartTime = this._taskStartTime;
		copy._taskEndTime = this._taskEndTime;
		copy._isDone = this._isDone;
		copy._tagsSet = (HashSet<String>) this._tagsSet.clone();
		return copy;
	}
	
	//@author A0094762W
	@Override
	public int compareTo(DSTask task) {
		int compareStatusResult = compareStatus(task);
		if (!isCompareResultsEqual(compareStatusResult)) {
			return compareStatusResult;
		}

		int compareDateResult = compareDate(task);
		if (!isCompareResultsEqual(compareDateResult)) {
			return compareDateResult;
		}

		int compareTimeResult = compareTime(task);
		if (!isCompareResultsEqual(compareTimeResult)) {
			return compareTimeResult;
		}

		int compareNameResult = compareName(task);

		return compareNameResult;
	}

	private boolean isCompareResultsEqual(int compareStatusResult) {
		return compareStatusResult == COMPARE_EQUAL;
	}

	/**
	 * Returns negative int if this status is higher in rank and positive if
	 * lower, otherwise return 0. Ranking is as follows:
	 * OVERDUE > NOT_DONE = IN_PROCESS > DONE
	 * 
	 * @param task
	 */
	private int compareStatus(DSTask task) {
		if (rankingIsEqual(task)) {
			return COMPARE_EQUAL;
		} else if (thisIsHigherRanking(task)) {
			return COMPARE_SMALLER_THAN;
		} else {
			return COMPARE_LARGER_THAN;
		}
	}

	private boolean rankingIsEqual(DSTask task) {
		return bothStatusAreEqual(task) || bothAreNotDoneOrInProcess(task);
	}

	private boolean bothStatusAreEqual(DSTask task) {
		return this.getStatus() == task.getStatus();
	}

	private boolean bothAreNotDoneOrInProcess(DSTask task) {
		return isNotDoneOrInProcess(this) && isNotDoneOrInProcess(task);
	}

	private boolean isNotDoneOrInProcess(DSTask task) {
		return task.getStatus() == NOT_DONE || task.getStatus() == IN_PROCESS;
	}

	private boolean thisIsHigherRanking(DSTask task) {
		return statusIsOverdue(this) ||
					 thisIsNotDoneOrInProcessAndTaskIsNotOverdue(task);
	}

	private boolean statusIsOverdue(DSTask task) {
		return task.getStatus() == OVERDUE;
	}

	private boolean thisIsNotDoneOrInProcessAndTaskIsNotOverdue(DSTask task) {
		return isNotDoneOrInProcess(this) && !statusIsOverdue(task);
	}

	private int compareDate(DSTask task) {
		Date thisDate = this.getTaskStartDate();
		Date taskDate = task.getTaskStartDate();
		
		if (hasNoDateForBothTasks(thisDate, taskDate)) {
			return compareEndDate(task);
		} else if (hasDateForThisOnly(thisDate, taskDate)) {
			return compareStartDateOfThisWithEndDateOfTask(task, thisDate);
		} else if (hasDateForTaskOnly(thisDate, taskDate)) {
			return compareStartDateOfTaskWithEndDateOfThis(task, taskDate);
		} else if (hasDateForBothTask(thisDate, taskDate)) {
			return compareDatesWithConsiderationToInProcessTasks(task, thisDate,
																													 taskDate);
		} else {
			return indicateUndefinedBehaviour();
		}
	}

	private int indicateUndefinedBehaviour() {
		System.out.println("Error: Undefined Behaviour");
		return Integer.MAX_VALUE;
	}

	private int compareDatesWithConsiderationToInProcessTasks(DSTask task,
																														Date thisDate,
																														Date taskDate) {
		if (thisDate.equals(taskDate) ||
				(this.getStatus() == IN_PROCESS && task.getStatus() == IN_PROCESS)) {
			return compareEndDate(task);
		} else if (this.getStatus() == IN_PROCESS) {
			return compareResultWhenThisIsInProcess(taskDate);
		} else if (task.getStatus() == IN_PROCESS) {
			return compareResultWhenTaskIsInProcess(task, thisDate);
		} else {
			return thisDate.compareTo(taskDate);
		}
	}

	private int compareStartDateOfTaskWithEndDateOfThis(DSTask task, Date taskDate) {
		Date thisDate = this.getTaskEndDate();
		if (!this.hasEndDate()) {
			return COMPARE_SMALLER_THAN;
		} else if (task.getStatus() == IN_PROCESS) {
			return compareResultWhenTaskIsInProcess(task, thisDate);
		} else {
			return compareDatesWhereTaskWinsTieBreak(thisDate, taskDate);
		}
	}
	
	private int compareStartDateOfThisWithEndDateOfTask(DSTask task, Date thisDate) {
		Date taskDate = task.getTaskEndDate();
		if (!task.hasEndDate()) {
			return COMPARE_LARGER_THAN;
		} else if (this.getStatus() == IN_PROCESS) {
			return compareResultWhenThisIsInProcess(taskDate);
		} else {
			return compareDatesWhereThisWinsTieBreak(taskDate, thisDate);
		}
	}

	private int compareResultWhenThisIsInProcess(Date taskDate) {
		Date thisDate = this.getTaskEndDate();
		return compareDatesWhereThisWinsTieBreak(taskDate, thisDate);
	}
	
	private int compareResultWhenTaskIsInProcess(DSTask task, Date thisDate) {
		Date taskDate = task.getTaskEndDate();
		return compareDatesWhereTaskWinsTieBreak(thisDate, taskDate);
	}

	private int compareDatesWhereThisWinsTieBreak(Date taskDate, Date thisDate) {
		int compareResult = thisDate.compareTo(taskDate);

		return compareResultWhereThisWinsTieBreak(compareResult);
	}

	private int compareDatesWhereTaskWinsTieBreak(Date thisDate, Date taskDate) {
		int compareResult = thisDate.compareTo(taskDate);

		return compareResultWhereTaskWinsTieBreak(compareResult);
	}
	
	private int compareResultWhereTaskWinsTieBreak(int compareResult) {
		return compareResult == COMPARE_EQUAL ? COMPARE_LARGER_THAN : compareResult;
	}

	private int compareResultWhereThisWinsTieBreak(int compareResult) {
		return compareResult == COMPARE_EQUAL ? COMPARE_SMALLER_THAN : compareResult;
	}
	
	private boolean hasNoDateForBothTasks(Date thisDate, Date taskDate) {
		return formatDateToString(thisDate).equals(DEFAULT_DATE) &&
				 	 formatDateToString(taskDate).equals(DEFAULT_DATE);
	}
	
	private boolean hasDateForThisOnly(Date thisDate, Date taskDate) {
		return !formatDateToString(thisDate).equals(DEFAULT_DATE) &&
					 formatDateToString(taskDate).equals(DEFAULT_DATE);
	}
	
	private boolean hasDateForTaskOnly(Date thisDate, Date taskDate) {
		return formatDateToString(thisDate).equals(DEFAULT_DATE) &&
					 !formatDateToString(taskDate).equals(DEFAULT_DATE);
	}
	
	private boolean hasDateForBothTask(Date thisDate, Date taskDate) {
		return !formatDateToString(thisDate).equals(DEFAULT_DATE) &&
				 	 !formatDateToString(taskDate).equals(DEFAULT_DATE);
	}

	private int compareEndDate(DSTask task) {
		Date thisDate = this.getTaskEndDate();
		Date taskDate = task.getTaskEndDate();
		
		if (hasNoDateForBothTasks(thisDate, taskDate)) {
			return COMPARE_EQUAL;
		} else if (hasDateForThisOnly(thisDate, taskDate)) {
			return COMPARE_LARGER_THAN;
		} else if (hasDateForTaskOnly(thisDate, taskDate)) {
			return COMPARE_SMALLER_THAN;
		} else if (hasDateForBothTask(thisDate, taskDate)){
			return thisDate.compareTo(taskDate);
		} else {
			return indicateUndefinedBehaviour();
		}
	}

	private int compareTime(DSTask task) {
		int thisTime = this.getTaskStartTime();
		int taskTime = task.getTaskStartTime();
		if (hasNoTimeForBothTasks(thisTime, taskTime)) {
			return compareEndTime(task);
		} else if (hasTimeForThisOnly(thisTime, taskTime)) {
			return compareStartTimeOfThisWithEndTimeOfTask(task, thisTime);
		} else if (hasTimeForTaskOnly(thisTime, taskTime)) {
			return compareStartTimeOfTaskWithEndTimeOfThis(taskTime);
		} else if (hasTimeForBothTasks(thisTime, taskTime)){
			return compareTimeWithConsiderationToInProcessTasks(task, thisTime, taskTime);
		} else {
			return indicateUndefinedBehaviour();
		}
	}
	
	private int compareTimeWithConsiderationToInProcessTasks(DSTask task,
																													 int thisTime,
																													 int taskTime) {
		if (thisTime == taskTime ||
				(this.getStatus() == IN_PROCESS && task.getStatus() == IN_PROCESS)) {
			return compareEndTime(task);
		} else if (this.getStatus() == IN_PROCESS) {
			return compareTimeResultWhenThisIsInProcess(taskTime);
		} else if (task.getStatus() == IN_PROCESS) {
			return compareTimeResultWhenTaskIsInProcess(task, thisTime);
		} else {
			return Integer.compare(thisTime, taskTime);
		}
	}

	private int compareTimeResultWhenTaskIsInProcess(DSTask task, int thisTime) {
		int taskTime = task.getTaskEndTime();
		return compareTimeWhereTaskWinsTieBreak(thisTime, taskTime);
	}
	
	private int compareTimeResultWhenThisIsInProcess(int taskTime) {
		int thisTime = this.getTaskEndTime();
		return compareTimeWhereThisWinsTieBreak(thisTime, taskTime);
	}

	private int compareStartTimeOfTaskWithEndTimeOfThis(int taskTime) {
		int thisTime;
		thisTime = this.getTaskEndTime();
		if (thisTime == DEFAULT_TIME) {
			return COMPARE_SMALLER_THAN;
		} else {
			return compareTimeWhereTaskWinsTieBreak(thisTime, taskTime);
		}
	}

	private int compareStartTimeOfThisWithEndTimeOfTask(DSTask task, int thisTime) {
		int taskTime;
		taskTime = task.getTaskEndTime();
		if (taskTime == DEFAULT_TIME) {
			return COMPARE_LARGER_THAN;
		} else {
			return compareTimeWhereThisWinsTieBreak(thisTime, taskTime);
		}
	}

	private int compareTimeWhereTaskWinsTieBreak(int thisTime, int taskTime) {
		int compareResult = Integer.compare(thisTime, taskTime);

		return compareResultWhereTaskWinsTieBreak(compareResult);
	}

	private int compareTimeWhereThisWinsTieBreak(int thisTime, int taskTime) {
		int compareResult = Integer.compare(thisTime, taskTime);

		return compareResultWhereThisWinsTieBreak(compareResult);
	}
	
	private boolean hasTimeForBothTasks(int thisTime, int taskTime) {
		return thisTime != DEFAULT_TIME && taskTime != DEFAULT_TIME;
	}

	private boolean hasTimeForTaskOnly(int thisTime, int taskTime) {
		return thisTime == DEFAULT_TIME && taskTime != DEFAULT_TIME;
	}

	private boolean hasTimeForThisOnly(int thisTime, int taskTime) {
		return thisTime != DEFAULT_TIME && taskTime == DEFAULT_TIME;
	}

	private boolean hasNoTimeForBothTasks(int thisTime, int taskTime) {
		return thisTime == DEFAULT_TIME && taskTime == DEFAULT_TIME;
	}

	private int compareEndTime(DSTask task) {
		int thisTime = this.getTaskEndTime();
		int taskTime = task.getTaskEndTime();

		if (hasNoTimeForBothTasks(thisTime, taskTime)) {
			return COMPARE_EQUAL;
		} else if (hasTimeForThisOnly(thisTime, taskTime)) {
			return COMPARE_LARGER_THAN;
		} else if (hasTimeForTaskOnly(thisTime, taskTime)) {
			return COMPARE_SMALLER_THAN;
		} else if (hasTimeForBothTasks(thisTime, taskTime)){
			return Integer.compare(thisTime, taskTime);
		} else {
			return indicateUndefinedBehaviour();
		}
	}

	private int compareName(DSTask task) {
		String thisName = this.getTaskName();
		String taskName = task.getTaskName();

		return thisName.compareToIgnoreCase(taskName);

	}

	private String formatDateToString(Date date) {
		return _formatter.format(date);
	}

	private Date formatStringToDate(String dateString) {
		try {
			return _formatter.parse(dateString);
		} catch (ParseException e) {
			System.out.println("Unable to parse date: \"" + dateString + "\"");
			e.printStackTrace();
		}

		return null;
	}

	//@author A0105536L
	/**
	 * This method is to show date in a fix format
	 * 
	 * @return Return a string
	 * @throws ParseException
	 */
	private String showDate() throws ParseException {
		if (this._taskEndDate.equals(this._formatter.parse(DEFAULT_DATE))
				&& this._taskStartDate.equals(this._formatter
						.parse(DEFAULT_DATE))) {
			// No start date and end date
			return "";
		} else if (!this._taskEndDate.equals(this._formatter
				.parse(DEFAULT_DATE))
				&& this._taskStartDate.equals(this._formatter
						.parse(DEFAULT_DATE))) {
			// only end date
			return "by" + " " + getTaskEndDateString() + " "
					+ this.showEndTime();
		} else {
			return "from" + " " + this.getTaskStartDateString() + " "
					+ this.showStartTime() + " " + "to" + " "
					+ this.getTaskEndDateString() + " " + this.showEndTime();
		}
	}

	/**
	 * This method is to show start time
	 * 
	 * @return Return a string
	 * @throws ParseException
	 */
	private String showStartTime() throws ParseException {
		if (this._taskStartTime == DEFAULT_TIME) {
			return "";
		} else {
			return String.format("%02d", this._taskStartTime / 100) + ":"
					+ String.format("%02d", this._taskStartTime % 100);
		}
	}

	/**
	 * This method is to show end time
	 * 
	 * @return Return a string
	 * @throws ParseException
	 */
	private String showEndTime() throws ParseException {
		if (this._taskEndTime == DEFAULT_TIME) {
			return "";
		} else {
			return String.format("%02d", this._taskEndTime / 100) + ":"
					+ String.format("%02d", this._taskEndTime % 100);
		}
	}
}